/**
 * 
 */
package com.dalonedrow.engine.ui.impl;

import com.dalonedrow.engine.sprite.base.SimpleDimension;
import com.dalonedrow.engine.sprite.base.SpriteBase;
import com.dalonedrow.engine.sprite.base.SpriteImageObject;
import com.dalonedrow.engine.sprite.base.SpriteImageObjectFactory;
import com.dalonedrow.engine.sprite.impl.BasicSpriteObject;
import com.dalonedrow.engine.systems.GameFont;
import com.dalonedrow.engine.systems.JOGLErrorHandler;
import com.dalonedrow.engine.systems.base.ProjectConstants;
import com.dalonedrow.engine.ui.base.GuiComponent;
import com.dalonedrow.engine.ui.base.border.Abstract1ColorBorder;
import com.dalonedrow.engine.ui.base.border.Abstract1ColorWithLinesBorder;
import com.dalonedrow.engine.ui.base.border.Abstract8ImageBorder;
import com.dalonedrow.engine.ui.base.border.Abstract8ImageBorderWithLines;
import com.dalonedrow.engine.ui.base.border.Abstract8ImageBorderWithLinesAndGradient;
import com.dalonedrow.engine.ui.base.border.Abstract8ImageNoBackgroundBorder;
import com.dalonedrow.engine.ui.base.border.Abstract8x4ImageBorder;
import com.dalonedrow.engine.ui.base.border.BorderFactory;
import com.dalonedrow.engine.ui.base.border.GuiBorder;
import com.dalonedrow.engine.ui.base.menu.MenuItem;
import com.dalonedrow.engine.ui.impl.border.EmptyBorder;
import com.dalonedrow.engine.ui.impl.border.H1SelectionBorder;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;
import com.dalonedrow.pooled.PooledStringBuilder;
import com.dalonedrow.pooled.StringBuilderPool;

/**
 * Factory class for producing standardized UI widgets.
 * @author Donald
 */
public final class UIFactory {
	/** the one and only instance of the <code>UIFactory</code> class. */
	private static UIFactory	instance;
	/**
	 * UIFactory Gives access to the singleton instance of {@link UIFactory}.
	 * @return {@link UIFactory}
	 */
	public static UIFactory getInstance() {
		if (UIFactory.instance == null) {
			UIFactory.instance = new UIFactory();
		}
		return UIFactory.instance;
	}
	/** Hidden constructor. */
	private UIFactory() { }
	/**
	 * Gets the maximum size for a character in a specific font.
	 * @param font the name of the font
	 * @return {@link SimpleDimension}
	 * @throws Exception if an error occurs
	 */
	public SimpleDimension getFontCharacterMetrics(final int fontId)
			throws Exception {
		return GameFont.getInstance().getFontById(fontId).getMaxCharMetrics();
	}
	/**
	 * Gets the maximum size for a character in a specific font.
	 * @param font the name of the font
	 * @return {@link SimpleDimension}
	 * @throws Exception if an error occurs
	 */
	public SimpleDimension getFontCharacterMetrics(final String font)
			throws Exception {
		return GameFont.getInstance().getFontByName(font).getMaxCharMetrics();
	}
	/**
	 * Gets the maximum size for a character in the H1 font.
	 * @return {@link SimpleDimension}
	 * @throws Exception if an error occurs
	 */
	public SimpleDimension getH1FontCharacterMetrics() throws Exception {
		String font = ProjectConstants.getInstance().getFontH1();
		return GameFont.getInstance().getFontByName(font).getMaxCharMetrics();
	}
	/**
	 * Gets a blank spacer label intended to create space between elements.
	 * @param width the spacer's width
	 * @param height the spacer's height
	 * @return {@link Label}
	 */
	public Label getSpacer(final int width, final int height) {
		Label l = UIFactory.getInstance().getStandardH1Label("");
		l.setBorder(new EmptyBorder(height, width, 0, 0));
		return l;
	}
	/**
	 * Gets a standard button item.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardButton(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Button button = getStandardButton(sb.toString());
		sb.returnToPool();
		return button;
	}
	/**
	 * Gets a standard button item.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardButton(final String text) {
		Button item = new Button(
				ProjectConstants.getInstance().getFontNormal(),
				text
				);
		item.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		return item;
	}
	/**
	 * Gets a standard H1 button.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardH1Button(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Button button = getStandardH1Button(sb.toString());
		sb.returnToPool();
		return button;
	}
	/**
	 * Gets a standard H1 button.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardH1Button(final String text) {
		Button button = new Button(
				ProjectConstants.getInstance().getFontH1(),
				text
				);
		button.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		button.setInactiveColor(
				ProjectConstants.getInstance().getInactiveFontColor());
		return button;
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardH1Label(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Label label = getStandardH1Label(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardH1Label(final int text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		sb.append(text);
		Label label = getStandardH1Label(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardH1Label(final String text) {
		return getStandardH1Label(text, false);
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @param debug the flag indicating whether the Label needs debugging turned
	 *        on
	 * @return {@link Label}
	 */
	public Label getStandardH1Label(final String text, final boolean debug) {
		Label label = new Label(
				ProjectConstants.getInstance().getFontH1(),
				text,
				debug
				);
		label.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		return label;
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public SimpleScrollingTextWindow getStandardH1SimpleScrollingTextWindow(
			final String text, final int maxLines, final int maxChars) {
		return getStandardH1SimpleScrollingTextWindow(
				text, maxLines, maxChars, false);
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @param debug the flag indicating whether the Label needs debugging turned
	 *        on
	 * @return {@link Label}
	 */
	public SimpleScrollingTextWindow getStandardH1SimpleScrollingTextWindow(
			final String text, final int maxLines, final int maxChars,
			final boolean debug) {
		SimpleScrollingTextWindow tw = new SimpleScrollingTextWindow(
				ProjectConstants.getInstance().getFontH1(),
				text,
				maxLines,
				maxChars,
				debug
				);
		tw.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		return tw;
	}
	/**
	 * Gets a standard H1 button.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardH2Button(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Button button = getStandardH2Button(sb.toString());
		sb.returnToPool();
		return button;
	}
	/**
	 * Gets a standard H1 button.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardH2Button(final String text) {
		Button button = new Button(
				ProjectConstants.getInstance().getFontH2(),
				text
				);
		button.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		button.setInactiveColor(
				ProjectConstants.getInstance().getInactiveFontColor());
		return button;
	}
	/**
	 * Gets a standard H2 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardH2Label(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Label label = getStandardH2Label(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a standard H1 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardH2Label(final int text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		sb.append(text);
		Label label = getStandardH2Label(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a standard H2 label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardH2Label(final String text) {
		Label label = new Label(
				ProjectConstants.getInstance().getFontH2(),
				text
				);
		label.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		return label;
	}
	/**
	 * Gets a {@link Button} with an icon.
	 * @param imageRefId the reference id for the icon image
	 * @return {@link Button}
	 * @throws Exception if an error occurs
	 */
	public Button getStandardImageButton(final int imageRefId)
			throws Exception {
		return getStandardImageButton(SpriteImageObjectFactory.getInstance()
				.getImageById(
						imageRefId));
	}
	/**
	 * Gets a {@link Button} with an icon.
	 * @param image the icon image
	 * @return {@link Button}
	 * @throws Exception if an error occurs
	 */
	public Button getStandardImageButton(final SpriteImageObject image)
			throws Exception {
		SpriteBase sb = new BasicSpriteObject();
		sb.setImageRefId(image.getRefId());
		sb.setWidth(image.getWidth());
		sb.setHeight(image.getHeight());
		Button button = new Button(sb);
		sb = null;
		return button;
	}
	/**
	 * Gets a {@link Button} with an icon.
	 * @param imageName the reference name for the icon image
	 * @return {@link Button}
	 * @throws Exception if an error occurs
	 */
	public Button getStandardImageButton(final String imageName)
			throws Exception {
		return this.getStandardImageButton(
				SpriteImageObjectFactory.getInstance().getImageByName(
						imageName));
	}
	/**
	 * Gets a {@link Button} with an icon and a separate icon used then the
	 * {@link Button} is hovered.
	 * @param iconImageName the {@link Button}'s normal icon
	 * @param highlightedIconImageName the {@link Button}'s icon when
	 *        highlighted
	 * @return {@link Button}
	 * @throws Exception if an error occurs
	 */
	public Button getStandardImageButton(final String iconImageName,
			final String highlightedIconImageName) throws Exception {
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject image =
				SpriteImageObjectFactory.getInstance().getImageByName(
						iconImageName);
		sb.setImageRefId(image.getRefId());
		sb.setWidth(image.getWidth());
		sb.setHeight(image.getHeight());
		final int standard =
				SpriteImageObjectFactory.getInstance().getImageRefId(
						iconImageName);
		final int highlighted =
				SpriteImageObjectFactory.getInstance().getImageRefId(
						highlightedIconImageName);
		Button button = new Button(sb) {
			/**
			 * {@inheritDoc}
			 */
			@Override
			public boolean onHighlight(final boolean value) {
				boolean val = super.onHighlight(value);
				try {
					if (val) {
						super.getSprite().setImageRefId(highlighted);
					} else {
						super.getSprite().setImageRefId(standard);
					}
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
				return val;
			}
		};
		return button;
	}
	/**
	 * Gets a {@link Button} with an icon and a separate icon used then the
	 * {@link Button} is hovered.
	 * @param iconImageName the {@link Button}'s normal icon
	 * @param highlightedIconImageName the {@link Button}'s icon when
	 *        highlighted
	 * @param iconDisabledImageName the {@link Button}'s icon when disabled
	 * @return {@link Button}
	 * @throws Exception if an error occurs
	 */
	public Button getStandardImageButton(final String iconImageName,
			final String highlightedIconImageName,
			final String iconDisabledImageName) throws Exception {
		SpriteBase sb = new BasicSpriteObject();
		SpriteImageObject image =
				SpriteImageObjectFactory.getInstance().getImageByName(
						iconImageName);
		sb.setImageRefId(image.getRefId());
		sb.setWidth(image.getWidth());
		sb.setHeight(image.getHeight());
		final int standard =
				SpriteImageObjectFactory.getInstance().getImageRefId(
						iconImageName);
		final int highlighted =
				SpriteImageObjectFactory.getInstance().getImageRefId(
						highlightedIconImageName);
		final int disabled =
				SpriteImageObjectFactory.getInstance().getImageRefId(
						iconDisabledImageName);
		System.out.println("ref for " + iconImageName + "::" + standard);
		System.out.println("ref for " + highlightedIconImageName + "::"
				+ highlighted);
		System.out
				.println("ref for " + iconDisabledImageName + "::" + disabled);
		Button button = new Button(sb) {
			/**
			 * {@inheritDoc}
			 */
			@Override
			public boolean onHighlight(final boolean value) {
				boolean val = super.onHighlight(value);
				try {
					if (val) {
						super.getSprite().setImageRefId(highlighted);
					} else {
						if (super.isActive()) {
							super.getSprite().setImageRefId(standard);
						} else {
							super.getSprite().setImageRefId(disabled);
						}
					}
				} catch (Exception ex) {
					JOGLErrorHandler.getInstance().fatalError(ex);
				}
				return val;
			}
			/**
			 * {@inheritDoc}
			 */
			@Override
			public void setActive(final boolean isActive) {
				super.setActive(isActive);
				if (super.isActive()) {
					super.getSprite().setImageRefId(standard);
				} else {
					super.getSprite().setImageRefId(disabled);
				}
			};
		};
		return button;
	}
	/**
	 * Gets a {@link Button} with an icon.
	 * @param imageRefId the reference id for the icon image
	 * @return {@link Button}
	 * @throws Exception if an error occurs
	 */
	public Label getStandardImageLabel(final int imageRefId)
			throws Exception {
		return getStandardImageLabel(SpriteImageObjectFactory.getInstance()
				.getImageById(
						imageRefId));
	}
	/**
	 * Gets a {@link Label} with an icon.
	 * @param image the icon image
	 * @return {@link Label}
	 * @throws Exception if an error occurs
	 */
	public Label getStandardImageLabel(final SpriteImageObject image)
			throws Exception {
		SpriteBase sb = new BasicSpriteObject();
		sb.setImageRefId(image.getRefId());
		sb.setWidth(image.getWidth());
		sb.setHeight(image.getHeight());
		Label label = new Label(sb);
		sb = null;
		return label;
	}
	/**
	 * Gets a {@link Label} with an icon.
	 * @param imageName the reference name for the icon image
	 * @return {@link Label}
	 * @throws Exception if an error occurs
	 */
	public Label getStandardImageLabel(final String imageName)
			throws Exception {
		return this.getStandardImageLabel(
				SpriteImageObjectFactory.getInstance().getImageByName(
						imageName));
	}
	/**
	 * Gets a standard label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardLabel(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Label label = getStandardLabel(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a standard label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardLabel(final int text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		sb.append(text);
		Label label = getStandardLabel(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a standard label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getStandardLabel(final String text) {
		return getStandardH1Label(text, false);
	}
	/**
	 * Gets a standard label.
	 * @param text the label's text
	 * @param debug the flag indicating whether the Label needs debugging turned
	 *        on
	 * @return {@link Label}
	 */
	public Label getStandardLabel(final String text, final boolean debug) {
		Label label = new Label(
				ProjectConstants.getInstance().getFontNormal(),
				text,
				debug
				);
		label.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		return label;
	}
	/**
	 * Gets a standard menu item, with an arrow highlight.
	 * @param text the menu item's text
	 * @return {@link MenuItem}
	 */
	public MenuItem getStandardMenuItem(final String text) {
		MenuItem item = new MenuItem(
				ProjectConstants.getInstance().getFontH1(),
				text
				);
		System.out.println("getStandardMenuItem()");
		System.out.println(ProjectConstants.getInstance().getFontH1());
		System.out
				.println(ProjectConstants.getInstance().getDefaultFontColor());
		item.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		item.setAlignment(GuiComponent.CENTER, GuiComponent.CENTER);
		item.setHighlightBorder(new H1SelectionBorder());
		return item;
	}
	/**
	 * Gets a standard H1 button.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardTitleButton(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Button button = getStandardTitleButton(sb.toString());
		sb.returnToPool();
		return button;
	}
	/**
	 * Gets a standard H1 button.
	 * @param text the button's text
	 * @return {@link Button}
	 */
	public Button getStandardTitleButton(final String text) {
		Button button = new Button(
				ProjectConstants.getInstance().getFontTitle(),
				text
				);
		button.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		button.setInactiveColor(
				ProjectConstants.getInstance().getInactiveFontColor());
		return button;
	}
	/**
	 * Gets a title label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getTitleLabel(final char[] text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		for (int i = 0; i < text.length; i++) {
			sb.append(text[i]);
		}
		Label label = getTitleLabel(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a title label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getTitleLabel(final int text) {
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		sb.append(text);
		Label label = getTitleLabel(sb.toString());
		sb.returnToPool();
		return label;
	}
	/**
	 * Gets a title label.
	 * @param text the label's text
	 * @return {@link Label}
	 */
	public Label getTitleLabel(final String text) {
		return getTitleLabel(text, false);
	}
	/**
	 * Gets a title label.
	 * @param text the label's text
	 * @param debug the flag indicating whether the Label needs debugging turned
	 *        on
	 * @return {@link Label}
	 */
	public Label getTitleLabel(final String text, final boolean debug) {
		Label label = new Label(
				ProjectConstants.getInstance().getFontTitle(),
				text,
				debug
				);
		label.setColor(ProjectConstants.getInstance().getDefaultFontColor());
		return label;
	}
	/**
	 * Gets a VX-Style dialog border, consisting of a series of border images,
	 * and a two-color gradient background with white lines beneath.
	 * @return {@link GuiBorder}
	 * @throws Exception if an error occurs
	 */
	public GuiBorder getVXStyleDialogBorder() throws Exception {
		return BorderFactory.getInstance()
				.getBorderEdgeOf8Images2ColorGradientBackgroundWithLines(
				ProjectConstants.getInstance().getVXStyleDialogInsets(),
				ProjectConstants.getInstance().getVXStyleDialogBorderImages(),
				ProjectConstants.getInstance().getVXStyleDialogGradientTop(),
				ProjectConstants.getInstance().getVXStyleDialogGradientBottom(),
				ProjectConstants.getInstance().getVXStyleDialogXOffset(),
				ProjectConstants.getInstance().getVXStyleDialogYOffset());
	}
	/**
	 * Gets a VX-Style dialog border, consisting of a series of border images,
	 * and a two-color gradient background with white lines beneath.
	 * @return {@link GuiBorder}
	 * @throws Exception if an error occurs
	 */
	public GuiBorder getVXStyleSpeechBorder() throws Exception {
		return BorderFactory.getInstance()
				.getBorderEdgeOf8Images2ColorGradientBackgroundWithLines(
				ProjectConstants.getInstance().getVXStyleSpeechInsets(),
				ProjectConstants.getInstance().getVXStyleSpeechBorderImages(),
				ProjectConstants.getInstance().getVXStyleSpeechGradientTop(),
				ProjectConstants.getInstance().getVXStyleSpeechGradientBottom(),
				ProjectConstants.getInstance().getVXStyleSpeechXOffset(),
				ProjectConstants.getInstance().getVXStyleSpeechYOffset());
	}
}
